package com.sweetcircle.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sweetcircle.domain.dto.MessageSendDto;
import com.sweetcircle.domain.dto.TokenUserInfoDto;
import com.sweetcircle.domain.enums.MessageTypeEnum;
import com.sweetcircle.domain.po.ChatMessage;
import com.sweetcircle.domain.po.ContactApply;
import com.sweetcircle.domain.po.UserContact;
import com.sweetcircle.domain.po.UserInfo;
import com.sweetcircle.domain.vo.UserInfoLoginVO;
import com.sweetcircle.domain.vo.UserInfoVO;
import com.sweetcircle.exception.BusinessException;
import com.sweetcircle.mapper.UserInfoMapper;
import com.sweetcircle.utils.AnanUtils;
import com.sweetcircle.utils.RedisComponet;
import com.sweetcircle.websocket.MessageHandler;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author hp
 * @description 针对表【user_info(用户信息)】的数据库操作Service实现
 * @createDate 2024-07-28 13:24:03
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Resource
    private RedisComponet redisComponet;

    @Resource
    private ContactApplyService contactApplyService;

    @Resource
    private UserContactService userContactService;

    @Resource
    private ChatMessageService chatMessageService;

    @Resource
    private MessageHandler messageHandler;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public HashMap<String, Object> login(UserInfoLoginVO userInfoLoginVO) {
        HashMap<String, Object> data = new HashMap<>();
        UserInfo userInfo;
        if(userInfoLoginVO.getEmail() != null) {
            // 根据邮箱查询用户信息
            userInfo = getByEmail(userInfoLoginVO.getEmail());
            if (userInfo == null) {
                throw new BusinessException(400, "邮箱未注册");
            }
            if (0 == userInfo.getStatus()) {
                throw new BusinessException(400, "该邮箱已禁用");
            }
        }else{
            userInfo = getByUserSweetCircleId(userInfoLoginVO.getUserSweetCircleId());
            if (userInfo == null) {
                throw new BusinessException(400, "账号无效");
            }
            if (0 == userInfo.getStatus()) {
                throw new BusinessException(400, "该账号已禁用");
            }
        }

        if (!AnanUtils.MD5Encryption(userInfoLoginVO.getPassword()).equals(userInfo.getPassword())) {
            throw new BusinessException(400, "密码错误");
        }

        //查询联系人
        List<HashMap<String, Object>> contactList = userContactService.getAllContact(userInfo.getUserId());

        // 判断用户是否已经登录
        Long lastHeartBeat = redisComponet.getUserHeartBeat(userInfo.getUserId());
        if (lastHeartBeat != null) {
            data.put("alreadyLogin", true);
        }

        // 根据用户当前token 查看redis中的用户信息
        TokenUserInfoDto tokenUserInfoDto = redisComponet.getTokenUserInfoDto(userInfoLoginVO.getToken());
        if (tokenUserInfoDto != null) {  // redis中存在 该用户 那
            AnanUtils.copyBean(userInfo, tokenUserInfoDto);  // 将userInfo中的信息覆盖到tokenUserInfoDto中
            tokenUserInfoDto.setToken(userInfoLoginVO.getToken());  // 不在重新生成登录token
        } else {  // 不存在该用户信息 重新生成token
            tokenUserInfoDto = AnanUtils.copyBean(userInfo, TokenUserInfoDto.class);  // 将userInfo中的信息拷贝到tokenUserInfoDto中
            tokenUserInfoDto.setToken(AnanUtils.getId());
        }
        // 查看该用户是否是 管理员
        tokenUserInfoDto.setAdmin(AnanUtils.verifyAdministrator(userInfo.getEmail()));
        // 保存用户信息到redis中
        redisComponet.saveTokenUserInfoDto(tokenUserInfoDto);

        // 将用户信息转换为VO对象 返回给前端
        UserInfoVO userInfoVO = AnanUtils.copyBean(userInfo, UserInfoVO.class);
        userInfoVO.setToken(tokenUserInfoDto.getToken());
        userInfoVO.setAdmin(tokenUserInfoDto.getAdmin()?1:0);
        redisComponet.removeCaptcha(userInfoLoginVO.getCaptchaKey());
        UserInfo updateInfo = new UserInfo();
        updateInfo.setLastLoginTime(System.currentTimeMillis());
        update(updateInfo, new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserId, userInfo.getUserId())
                .eq(UserInfo::getStatus, 1));
        List<ContactApply> listA = contactApplyService.list(new LambdaQueryWrapper<ContactApply>()  // 获取 好友申请消息
                .eq(ContactApply::getUserId, userInfo.getUserId()) // 我添加别人的
                .eq(ContactApply::getStatus,1));
        data.put("contactList", contactList);
        data.put("userInfo", userInfoVO);
        data.put("contactApplyList", listA);


        // 获取 离线 会话消息
        List<ChatMessage> list2 = chatMessageService.list(new LambdaQueryWrapper<ChatMessage>()
                .eq(ChatMessage::getContactId, userInfo.getUserId())
                .eq(ChatMessage::getSendStatus, 2)  // 未接收
                .eq(ChatMessage::getStatus, 1)
        );


        if (!list2.isEmpty()){
            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setSendStatus(1);
            boolean update = chatMessageService.update(chatMessage, new LambdaQueryWrapper<ChatMessage>()
                    .eq(ChatMessage::getContactId, userInfo.getUserId())
                    .eq(ChatMessage::getSendStatus, 2)  // 未接收
                    .eq(ChatMessage::getStatus, 1));
            if (!update){
                throw new BusinessException(400, "获取离线消息失败（更新发送状态失败）");
            }
            list2.forEach(chatMessage2 -> chatMessage2.setSendStatus(1));  // 修改所有的离线消息的发送状态为1已接收
        }



        data.put("offlineMessages", list2);

        // 更新用户最后登录时间
        UserInfo userInfo2 = new UserInfo();
        userInfo2.setLastLoginTime(System.currentTimeMillis());
        updateById(userInfo2);

        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(UserInfoLoginVO userInfoLoginVO) {
        long curDate = System.currentTimeMillis();  // 获取当前时间
        UserInfo userInfoA = getByEmail(userInfoLoginVO.getEmail());
        // 查询邮箱是否存在
        if (userInfoA != null) {
            throw new BusinessException(400, "邮箱已注册");
        }

        // 创建对象 用于保存在数据库
        UserInfo userInfo = AnanUtils.copyBean(userInfoLoginVO, UserInfo.class);
        String id = AnanUtils.getId();
        String userSweetCircleId = AnanUtils.getRandomString(ThreadLocalRandom.current().nextInt(6, 16));
        // 查看生成的ID 是否存在
        while (getById(id) != null) {
            id = AnanUtils.getId();
        }
        while (getByUserSweetCircleId(userSweetCircleId) != null) {
            userSweetCircleId = AnanUtils.getRandomString(ThreadLocalRandom.current().nextInt(6, 16));
        }
        // 重新设置密码 对密码加密
        userInfo.setPassword(AnanUtils.MD5Encryption(userInfoLoginVO.getPassword()));
        userInfo.setUserId(id);
        userInfo.setUserSweetCircleId(userSweetCircleId);
        userInfo.setCreateTime(curDate);
        userInfo.setLastLoginTime(curDate);
        // 插入数据
        boolean insert = save(userInfo);
        if (!insert) {
            throw new BusinessException(400, "注册失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(UserInfoLoginVO userInfoLoginVO) {
        String password = AnanUtils.MD5Encryption(userInfoLoginVO.getPassword());
        UserInfo userInfo = getByEmail(userInfoLoginVO.getEmail());
        if (password.equals(userInfo.getPassword())) {
            throw new BusinessException(400, "新密码不能与旧密码相同");
        }
        UserInfo u = new UserInfo(password);
        boolean update = update(u, new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getEmail, userInfoLoginVO.getEmail())
                .eq(UserInfo::getStatus, 1));
        if (!update) {
            throw new BusinessException(400, "重置密码失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserInfoVO updateUserInfo(UserInfoVO userInfoVO) {
        UserInfo userInfo = AnanUtils.copyBean(userInfoVO, UserInfo.class);
        boolean i = update(userInfo, new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserId, userInfo.getUserId())
                .eq(UserInfo::getStatus, 1));
        if (!i) {
            throw new BusinessException(400, "用户信息更新失败");
        }

        // 创建联系人 将将添加我为好友的用户的联系人更新
        UserContact userContact = new UserContact();
        userContact.setNickName(userInfoVO.getNickName());
        userContact.setSex(userInfoVO.getSex());
        userContact.setJoinType(userInfoVO.getJoinType());
        userContact.setAreaName(userInfoVO.getAreaName());
        userContact.setPersonalSignature(userInfoVO.getPersonalSignature());
        // 更新 添加我为好友的联系人信息 将我的信息更新到该用户的联系人信息
        boolean update = userContactService.update(userContact, new LambdaQueryWrapper<UserContact>()
                .eq(UserContact::getContactUserId, userInfo.getUserId())
                .eq(UserContact::getStatus, 1));
        if(!update){
            throw new BusinessException(400, "更新联系人信息失败");
        }

        // 获取 所有添加我为联系人的用户的userId
        List<String> userIdList = userContactService.list(new LambdaQueryWrapper<UserContact>()
                        .eq(UserContact::getContactUserId, userInfoVO.getUserId())
                        .eq(UserContact::getStatus, 1))
                .stream()
                .map(UserContact::getUserId)
                .toList();

        for (String userId : userIdList){  // 遍历所有添加我为联系人的用户的userId
            MessageSendDto messageSendDto = new MessageSendDto<>();
            messageSendDto.setMessageCode(1);
            messageSendDto.setSendUserId(userInfoVO.getUserId());
            messageSendDto.setContactId(userId);
            messageSendDto.setMessageType(MessageTypeEnum.UPDATE_FRIEND.getType());
            messageHandler.sendMessage(messageSendDto);  // 发送消息告知 联系人信息更新 从新获取联系人
        }

        UserInfo one = getOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserId, userInfoVO.getUserId())
                .eq(UserInfo::getStatus, 1));
        if (one == null) {
            throw new BusinessException(400, "用户信息更新失败");
        }
        // 将我的信息 保存到redis中
        redisComponet.saveTokenUserInfoDto(AnanUtils.copyBean(one, TokenUserInfoDto.class));

        return AnanUtils.copyBean(one, UserInfoVO.class);
    }


    private UserInfo getByEmail(String email) {
        return getOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getEmail, email)
                .eq(UserInfo::getStatus, 1));
    }
    private UserInfo getByUserSweetCircleId(String userSweetCircleId) {
        return getOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserSweetCircleId, userSweetCircleId)
                .eq(UserInfo::getStatus, 1));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserSweetCircleId(String userId, String userSweetCircleId) {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserSweetCircleId(userSweetCircleId);

        boolean update = update(userInfo, new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserId, userId)
                .eq(UserInfo::getStatus, 1));
        if (!update) {
            throw new BusinessException(400, "用户信息更新失败");
        }

        UserContact userContact = new UserContact();
        userContact.setContactUserSweetCircleId(userSweetCircleId);
        boolean update1 = userContactService.update(userContact, new LambdaQueryWrapper<UserContact>()
                .eq(UserContact::getContactUserId, userId)
                .eq(UserContact::getStatus, 1));
        if (!update1) {
            throw new BusinessException(400, "用户信息更新失败");
        }

        // 获取 所有添加我为联系人的用户的userId
        List<String> userIdList = userContactService.list(new LambdaQueryWrapper<UserContact>()
                        .eq(UserContact::getContactUserId, userId)
                        .eq(UserContact::getStatus, 1))
                .stream()
                .map(UserContact::getUserId)
                .toList();

        for (String userId2 : userIdList){  // 遍历所有添加我为联系人的用户的userId
            MessageSendDto messageSendDto = new MessageSendDto<>();
            messageSendDto.setMessageCode(1);
            messageSendDto.setSendUserId(userId);
            messageSendDto.setContactId(userId2);
            messageSendDto.setMessageType(MessageTypeEnum.UPDATE_FRIEND.getType());
            messageHandler.sendMessage(messageSendDto);  // 发送消息告知 联系人信息更新 从新获取联系人
        }

    }
}




